Java IO 理论笔记

1、Java IO 流

io是java中实现输入输出的基础,它可以很方便的完成数据的输入输出操作,Java把不同的输入输出抽象为流,通过流的方式允许Java程序使用相同的方式来访问不同的输入、输出。

2、流的分类

输入流、输出流 

A、输入流:只能从中读取数据,而不能向里面写数据

B、 输出流:只能向里面写数据,而不能读数据

可以这样理解,数据从内存到硬盘,通常认为是输出流,即写操作;相反,从硬盘到内存,通常认为是输入流,即读操作;这里的输入、输出是从内存的角度划分的

Java的输入流主要有InputStream和Reader作为基类,而输出流则主要由OutputStream和Writer作为基类;

 

字节流和字符流

字节流和字符流区别非常简单,它们的用法几乎一样。区别在于字节流和字符流所操作的数据单元不同:字节流操作的最小单元数据是8位字节,而字符流作为最小数据单元是16为字节。

字节流主要由InputStream、OutputStream作为基类,而字符流则主要由Reader和Writer作为基类完成。

节点流和处理流

按照流的角色分,可以分为节点流和处理流。

可以从、向一个特定的IO设备,读写数据流,称为节点流,节点流常常也被常务低级流(Low Level Stream)

处理流则用于对一个已经存在的流进行连接封装,通过封装后来实现数据的读写功能。处理流称为高级流;

当用处理流的进行输入、输出时,程序并不会直接连接到实际数据源,没有和实际的输入、输出节点连接。使用处理流一个明显的好处是:只要使用相同的处理流,程序就可以采用相同的输入、输出代码来访问不同数据源,随着处理流锁包装节点流的改变,程序实际所访问的数据源也相应发生改变。

处理流的功能主要体现在两个方面:

性能提高:主要以增加缓冲方式来提高输入、输出的效率

操作的便捷: 处理流可能提供了系列便捷的方法来一次性输入、输出大批量的内容,而不是输入、输出一个或多个单位数据

处理流可以“嫁接”在任何已经存在的流的基础上,这就允许Java应用程序采用相同的代码、透明的方式来访问不同的输入、输出设备输入流。

字节输入流InputStream和字符输入流Reader

InputStream和Reader是所有输入流的基类,他们都是2个抽象类,本身并不能创建实例来执行输入,但他们有输入流的模版,所以它们的方法是所有的输入流和输出流可以用的方法。

在InputStream里常用的方法:

int read(): 从输入流中读取单个自己

int read(byte[] b): 从输入流中读取最多b.length个字节,将读取的字节存在数组b中,返回实际读取的字节数

int read(byte[] b, int off, int len): 从输入流中读取最多len个字节数据,并将其存储在数字b中,放入b数组中时,并不是从数组起点开始,而是从off位置开始,返回实际读取字节数。

在Reader里经常使用的方法:

int read(): 从输入流中读取单个字符

int read(char[] c): 从输入流读取最多c.length个字符数据,并将其存储在字符数组c中,返回实际读取的字符

int read(char[] c, int off, int len): 从输入流中读取最多len个字符的数据,将读取的数据放到字符数组c中保存,从数组的off开始读取;

InputStream、Reader还支持如下几个方法移动指针:

void mark(int readAheadLimit): 在记录指针当前位置第一个标记(mark)

boolean markSupported(): 判断此输入流是否支持mark()操作,即是否支持记录标记

void reset():将此流的记录的指针重新定位到上一次记录的标记的位置

long skip(long n):记录指针向前移动n个字节、字符

OutputStream字节输出流和Writer字符输出流

具有以下方法:

void write(int c): 指定的字节、字符输出到输出流中

void write(byte[]/char[] buf): 将字节数组/字符数组中的数据传输到指定输出流中

void write(byte[]/char[] buf, int off,int len):将指定数组中的数据输出到指定输出流中

字符输出流还有以下方法:

void write(String s):将指定字符串输出到指定输出流中

void write(String s, int off, int len):将字节数组、字符数组中从off位置开始,长度为len的字节、字符输出到输出流中

3、Java的输入、输出流:

分类

字节输入流

字节输出流

字符输入流

字符输出流

抽象基类

InputStream

OutputStream

Reader

Writer

访问文件

FileInputStream

FileOutputStream

FileReader

FileWriter

访问数组

ByteArrayInputStream

ByteArrayOutputStream

CharArrayReader

CharArrayWriter

访问管道

PipedInputStream

PipedOutputStream

PipedReader

PipedWriter

访问字符串

   

StringReader

StringWriter

缓冲流

BufferedInputStream

BufferedOutputStream

BufferedReader

BufferedWriter

转换流

   

InputStreamReader

OutputStreamWriter

对象流

ObjectInputStream

ObjectOutputStream

   

抽象基类

FilterInputStream

FilterOutputStream

FilterReader

FilterWriter

打印流

 

PrintStream

 

PrintWriter

推回输入流

PushbackInputStream

 

PushbackReader

 

特殊流

DataInputStream

DataOutputStream

   

输入、输出流的体系:

推回输入流:

有2个特殊流与众不同,就是PushbackInputStream、PushbackReader,它们有以下常用方法:

void unread(byte[]/char[] buf):将一个字节/字符数组推到缓冲区里,运行重复读取推回的内容

void unread(byte[]/char[] buf, int off, int len):将一个字节/字符数组从off位置开始读取,长度是len的字符/字节数组的内容推回到缓冲区中,允许重复刚才读取的内容

void unread(int b):将一个字节、字符推回到缓冲区

这2个推回输入流都带一个缓冲区,当程序调用unread的时候,系统就会把指定数组的内容推回到缓冲区,而推回输入流每次调用read的方法,总会先去读取推回缓冲区中的内容,只有完全读取的缓冲区里面的内容后,而且还没有装满read所需的数组,才会到原输入流中读取内容;

重定向标准输入输出

在System中有3大标准输入、输出方法:

static void setErr(PrintStream e):重定向“标准”错误输出流

static void setIn(InputStream in):重定向“标准”输入流

static void setOut(OutputStream out):重定向“标准”输出流

JVM写其他进程数据

Runtime对象有exec方法,他可以运行jvm命令行,该方法产生一个Process对象,Process对象代表由该Java程序启动的子进程,Process类有以下方法,可以和子进程通信;

InputStream getErrorStream():获取子进程的错误流

InputStream getInputStream():获取子进程的输入流

OutputStream getOutputStream():获取子进程的输入流

4、RandomAccessFile

RandomAccessFile是Java输入、输出体系中功能最丰富的文件内容访问类,它提供了众多方法来访问文件内容,它既可以读文件内容也可以像文件输出数据。它和普通的输入、输出流不同的是,它可以随机访问的方式,操作文件数据。

RandomAccessFile可以自由定位文件指针,所以RandomAccessFile可以不从开始的地方输出,RandomAccessFile可以向已经存在的文件后追加内容。

RandomAccessFile对象包含一个指针用来记录当前读写的位置,当程序新创建一个RandomAccessFile对象时,该指针位于文件头部,既0的位置;当读取或写入了n个字节后,文件指针就指向最后的位置,除此之外,文件指针也是可以随意移动的,RandomAccessFile有以下方法操作指针:

long getFilePointer():返回文件记录指针的当前位置

void seek(long pos):将文件记录指针定位到pos位置

RandomAccessFile既可以读也可以写,所以它包含了完全类似于InputStream的read方法,和OutputStream的write方法,用法和原来的都一样;而且RandomAccessFile还包含了readXxx、writeXxx的输入输出方法;

RandomAccessFile的文件访问模式:

r:以只读方式打开指定文件

rw:以读取、写入方式打开指定文件,如果文件不存在就创建

rws:以读取、写入的方式打开指定文件,相对应rw模式,还要求文件内容和元数据的每个更新都同步写入到底层存储设备

rwd:以读取、写入方式打开指定文件,对于rw,还要求文件内容的每个更新都同步写入到底层设备

5、序列化

在远程调用、分布式开发中常用到序列化,将java对象序列化的文件中保存,然后在解析的时候又反序列化,其中需要用到Serializable接口;在实现了该接口的对象可以顺利序列化成一个文件保存在硬盘上,反序列化也是通过该接口的id来查找该对象的。

transient可以忽略对象中某个属性不被序列化。

6NIO

nio常用的包介绍:

java.io 包:主要提供了一些和Buffer相关的类

java.io.channels:包括Selector和Channel的相关类

java.nio.charset:包含和字符集相关的类

java.nio.channels.spi:提供Channel服务类

java.nio.charset.spi:提供文字集的服务类

Buffer介绍

Buffer是提取数据的容器,这里有ByteBuffer、CharBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer。

上面这些类,除了ByteBuffer之外,都采用类似的方法管理数据,只是各自管理的数据类型不同而已。这些Buffer都没有构造器,通过使用如下方法来得到一个Buffer对象:

static XxxBuffer allocate(int capacity) 创建一个容量为capacity的XxxBuffer对象

ByteBuffer的子类MappedByteBuffer,它用于表示Chanael将硬盘文件的的部分或全部内容映射到内存中后得到结果,通常MappedByteBuffer对象由Chanael的map方法返回。

在Buffer中有三个重要的概念:容量(capacity)、界限(limit)、位置(position)

容量(capacity):缓冲区的容量(capacity)表示该Buffer的最大数据容量,即最多可以存储多少数据,缓冲区的容量不能为负数,在创建后是不能改变的。

界限(limit):第一个不应该被读出或写入的缓冲区位置索引。也就是说,位于limit后的数据既不能读,也不能写。

位置(position):用于指明下一个可以读出的后者写入的缓冲区位置索引。类似于IO流中的记录指针位置。当刚刚新建一个Buffer对象时,容器position为0,如果从Channel读取了2个数据到该Buffer中,则postion为2,指向Buffer中的第三个。

Buffer常用方法:

int capacity():返回Buffer的capacity的大小

boolean hasRemaining():判断当前位置(position)和界限(limit)之间是否还有元素可以提供处理。

int limit:返回Buffer的界限(limit)的位置

Buffer limit(int newLimit)重新设置界限的值,并返回一个具有新的limit的缓冲区的对象

Buffer mark():设置Buffer的mark位置,它只能在0和位置position之间做mark

int position():返回当前Buffer的position

Buffer postion(int newPostion):设置Buffer的新位置,并返回一个具有新的limit的缓冲区对象。

int remaining():返回当前位置和界限之间的元素个数

Buffer reset():将position位置设置到mark的位置

Buffer rewind():将位置(position)设置为0,取消设置的mark

当使用put和get来访问Buffer中的数据时,分为绝对和相对的2种:

相对的Relative:从Buffer中的当前位置读取和写入数据,然后将位置(position)的值按处理元素的个数相加。

绝对Absolute:直接根据索引来向Buffer中读取或写入数据,使用绝对方式来访问Buffer理的数据,并不会影响位置position的值。

posted on 2011-05-09 11:16  hoojo  阅读(6115)  评论(2编辑  收藏  举报